home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2007 September / PCWSEP07.iso / Software / Linux / Linux Mint 3.0 Light / LinuxMint-3.0-Light.iso / casper / filesystem.squashfs / usr / lib / ruby / 1.8 / ipaddr.rb < prev    next >
Encoding:
Ruby Source  |  2006-08-04  |  20.6 KB  |  767 lines

  1. #
  2. # ipaddr.rb - A class to manipulate an IP address
  3. #
  4. # Copyright (c) 2002 Hajimu UMEMOTO <ume@mahoroba.org>.
  5. # All rights reserved.
  6. #
  7. # You can redistribute and/or modify it under the same terms as Ruby.
  8. #
  9. # $Id: ipaddr.rb,v 1.5.2.3 2006/08/04 22:00:21 drbrain Exp $
  10. #
  11. # TODO:
  12. #   - scope_id support
  13. require 'socket'
  14.  
  15. unless Socket.const_defined? "AF_INET6"
  16.   class Socket
  17.     AF_INET6 = Object.new
  18.   end
  19.  
  20.   class << IPSocket
  21.     def valid_v4?(addr)
  22.       if /\A(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\Z/ =~ addr
  23.         return $~.captures.all? {|i| i.to_i < 256}
  24.       end
  25.       return false
  26.     end
  27.  
  28.     def valid_v6?(addr)
  29.       # IPv6 (normal)
  30.       return true if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*\Z/ =~ addr
  31.       return true if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*)?\Z/ =~ addr
  32.       return true if /\A::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*)?\Z/ =~ addr
  33.       # IPv6 (IPv4 compat)
  34.       return true if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*:/ =~ addr && valid_v4?($')
  35.       return true if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*:)?/ =~ addr && valid_v4?($')
  36.       return true if /\A::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*:)?/ =~ addr && valid_v4?($')
  37.  
  38.       false
  39.     end
  40.  
  41.     def valid?(addr)
  42.       valid_v4?(addr) || valid_v6?(addr)
  43.     end
  44.  
  45.     alias getaddress_orig getaddress
  46.     def getaddress(s)
  47.       if valid?(s)
  48.         s
  49.       elsif /\A[-A-Za-z\d.]+\Z/ =~ s
  50.         getaddress_orig(s)
  51.       else
  52.         raise ArgumentError, "invalid address"
  53.       end
  54.     end
  55.   end
  56. end
  57.  
  58. # IPAddr provides a set of methods to manipulate an IP address.  Both IPv4 and
  59. # IPv6 are supported.
  60. #
  61. # == Example
  62. #
  63. #   require 'ipaddr'
  64. #   
  65. #   ipaddr1 = IPAddr.new "3ffe:505:2::1"
  66. #   
  67. #   p ipaddr1            #=> #<IPAddr: IPv6:3ffe:0505:0002:0000:0000:0000:0000:0001/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff>
  68. #   
  69. #   p ipaddr1.to_s        #=> "3ffe:505:2::1"
  70. #   
  71. #   ipaddr2 = ipaddr1.mask(48)    #=> #<IPAddr: IPv6:3ffe:0505:0002:0000:0000:0000:0000:0000/ffff:ffff:ffff:0000:0000:0000:0000:0000>
  72. #   
  73. #   p ipaddr2.to_s        #=> "3ffe:505:2::"
  74. #   
  75. #   ipaddr3 = IPAddr.new "192.168.2.0/24"
  76. #   
  77. #   p ipaddr3            #=> #<IPAddr: IPv4:192.168.2.0/255.255.255.0>
  78.  
  79. class IPAddr
  80.  
  81.   IN4MASK = 0xffffffff
  82.   IN6MASK = 0xffffffffffffffffffffffffffffffff
  83.   IN6FORMAT = (["%.4x"] * 8).join(':')
  84.  
  85.   # Returns the address family of this IP address.
  86.   attr :family
  87.  
  88.   # Creates a new ipaddr containing the given network byte ordered
  89.   # string form of an IP address.
  90.   def IPAddr::new_ntoh(addr)
  91.     return IPAddr.new(IPAddr::ntop(addr))
  92.   end
  93.  
  94.   # Convert a network byte ordered string form of an IP address into
  95.   # human readable form.
  96.   def IPAddr::ntop(addr)
  97.     case addr.size
  98.     when 4
  99.       s = addr.unpack('C4').join('.')
  100.     when 16
  101.       s = IN6FORMAT % addr.unpack('n8')
  102.     else
  103.       raise ArgumentError, "unsupported address family"
  104.     end
  105.     return s
  106.   end
  107.  
  108.   # Returns a new ipaddr built by bitwise AND.
  109.   def &(other)
  110.     return self.clone.set(@addr & other.to_i)
  111.   end
  112.  
  113.   # Returns a new ipaddr built by bitwise OR.
  114.   def |(other)
  115.     return self.clone.set(@addr | other.to_i)
  116.   end
  117.  
  118.   # Returns a new ipaddr built by bitwise right-shift.
  119.   def >>(num)
  120.     return self.clone.set(@addr >> num)
  121.   end
  122.  
  123.   # Returns a new ipaddr built by bitwise left shift.
  124.   def <<(num)
  125.     return self.clone.set(addr_mask(@addr << num))
  126.   end
  127.  
  128.   # Returns a new ipaddr built by bitwise negation.
  129.   def ~
  130.     return self.clone.set(addr_mask(~@addr))
  131.   end
  132.  
  133.   # Returns true if two ipaddr are equal.
  134.   def ==(other)
  135.     if other.kind_of?(IPAddr) && @family != other.family
  136.       return false
  137.     end
  138.     return (@addr == other.to_i)
  139.   end
  140.  
  141.   # Returns a new ipaddr built by masking IP address with the given
  142.   # prefixlen/netmask. (e.g. 8, 64, "255.255.255.0", etc.)
  143.   def mask(prefixlen)
  144.     return self.clone.mask!(prefixlen)
  145.   end
  146.  
  147.   # Returns true if the given ipaddr is in the range.
  148.   #
  149.   # e.g.:
  150.   #   require 'ipaddr'
  151.   #   net1 = IPAddr.new("192.168.2.0/24")
  152.   #   p net1.include?(IPAddr.new("192.168.2.0"))    #=> true
  153.   #   p net1.include?(IPAddr.new("192.168.2.255"))    #=> true
  154.   #   p net1.include?(IPAddr.new("192.168.3.0"))    #=> false
  155.   def include?(other)
  156.     if ipv4_mapped?
  157.       if (@mask_addr >> 32) != 0xffffffffffffffffffffffff
  158.     return false
  159.       end
  160.       mask_addr = (@mask_addr & IN4MASK)
  161.       addr = (@addr & IN4MASK)
  162.       family = Socket::AF_INET
  163.     else
  164.       mask_addr = @mask_addr
  165.       addr = @addr
  166.       family = @family
  167.     end
  168.     if other.kind_of?(IPAddr)
  169.       if other.ipv4_mapped?
  170.     other_addr = (other.to_i & IN4MASK)
  171.     other_family = Socket::AF_INET
  172.       else
  173.     other_addr = other.to_i
  174.     other_family = other.family
  175.       end
  176.     else # Not IPAddr - assume integer in same family as us
  177.       other_addr   = other.to_i
  178.       other_family = family
  179.     end
  180.  
  181.     if family != other_family
  182.       return false
  183.     end
  184.     return ((addr & mask_addr) == (other_addr & mask_addr))
  185.   end
  186.   alias === include?
  187.  
  188.   # Returns the integer representation of the ipaddr.
  189.   def to_i
  190.     return @addr
  191.   end
  192.  
  193.   # Returns a string containing the IP address representation.
  194.   def to_s
  195.     str = to_string
  196.     return str if ipv4?
  197.  
  198.     str.gsub!(/\b0{1,3}([\da-f]+)\b/i, '\1')
  199.     loop do
  200.       break if str.sub!(/\A0:0:0:0:0:0:0:0\Z/, '::')
  201.       break if str.sub!(/\b0:0:0:0:0:0:0\b/, ':')
  202.       break if str.sub!(/\b0:0:0:0:0:0\b/, ':')
  203.       break if str.sub!(/\b0:0:0:0:0\b/, ':')
  204.       break if str.sub!(/\b0:0:0:0\b/, ':')
  205.       break if str.sub!(/\b0:0:0\b/, ':')
  206.       break if str.sub!(/\b0:0\b/, ':')
  207.       break
  208.     end
  209.     str.sub!(/:{3,}/, '::')
  210.  
  211.     if /\A::(ffff:)?([\da-f]{1,4}):([\da-f]{1,4})\Z/i =~ str
  212.       str = sprintf('::%s%d.%d.%d.%d', $1, $2.hex / 256, $2.hex % 256, $3.hex / 256, $3.hex % 256)
  213.     end
  214.  
  215.     str
  216.   end
  217.  
  218.   # Returns a string containing the IP address representation in
  219.   # canonical form.
  220.   def to_string
  221.     return _to_string(@addr)
  222.   end
  223.  
  224.   # Returns a network byte ordered string form of the IP address.
  225.   def hton
  226.     case @family
  227.     when Socket::AF_INET
  228.       return [@addr].pack('N')
  229.     when Socket::AF_INET6
  230.       return (0..7).map { |i|
  231.     (@addr >> (112 - 16 * i)) & 0xffff
  232.       }.pack('n8')
  233.     else
  234.       raise "unsupported address family"
  235.     end
  236.   end
  237.  
  238.   # Returns true if the ipaddr is an IPv4 address.
  239.   def ipv4?
  240.     return @family == Socket::AF_INET
  241.   end
  242.  
  243.   # Returns true if the ipaddr is an IPv6 address.
  244.   def ipv6?
  245.     return @family == Socket::AF_INET6
  246.   end
  247.  
  248.   # Returns true if the ipaddr is an IPv4-mapped IPv6 address.
  249.   def ipv4_mapped?
  250.     return ipv6? && (@addr >> 32) == 0xffff
  251.   end
  252.  
  253.   # Returns true if the ipaddr is an IPv4-compatible IPv6 address.
  254.   def ipv4_compat?
  255.     if !ipv6? || (@addr >> 32) != 0
  256.       return false
  257.     end
  258.     a = (@addr & IN4MASK)
  259.     return a != 0 && a != 1
  260.   end
  261.  
  262.   # Returns a new ipaddr built by converting the native IPv4 address
  263.   # into an IPv4-mapped IPv6 address.
  264.   def ipv4_mapped
  265.     if !ipv4?
  266.       raise ArgumentError, "not an IPv4 address"
  267.     end
  268.     return self.clone.set(@addr | 0xffff00000000, Socket::AF_INET6)
  269.   end
  270.  
  271.   # Returns a new ipaddr built by converting the native IPv4 address
  272.   # into an IPv4-compatible IPv6 address.
  273.   def ipv4_compat
  274.     if !ipv4?
  275.       raise ArgumentError, "not an IPv4 address"
  276.     end
  277.     return self.clone.set(@addr, Socket::AF_INET6)
  278.   end
  279.  
  280.   # Returns a new ipaddr built by converting the IPv6 address into a
  281.   # native IPv4 address.  If the IP address is not an IPv4-mapped or
  282.   # IPv4-compatible IPv6 address, returns self.
  283.   def native
  284.     if !ipv4_mapped? && !ipv4_compat?
  285.       return self
  286.     end
  287.     return self.clone.set(@addr & IN4MASK, Socket::AF_INET)
  288.   end
  289.  
  290.   # Returns a string for DNS reverse lookup.  It returns a string in
  291.   # RFC3172 form for an IPv6 address.
  292.   def reverse
  293.     case @family
  294.     when Socket::AF_INET
  295.       return _reverse + ".in-addr.arpa"
  296.     when Socket::AF_INET6
  297.       return ip6_arpa
  298.     else
  299.       raise "unsupported address family"
  300.     end
  301.   end
  302.  
  303.   # Returns a string for DNS reverse lookup compatible with RFC3172.
  304.   def ip6_arpa
  305.     if !ipv6?
  306.       raise ArgumentError, "not an IPv6 address"
  307.     end
  308.     return _reverse + ".ip6.arpa"
  309.   end
  310.  
  311.   # Returns a string for DNS reverse lookup compatible with RFC1886.
  312.   def ip6_int
  313.     if !ipv6?
  314.       raise ArgumentError, "not an IPv6 address"
  315.     end
  316.     return _reverse + ".ip6.int"
  317.   end
  318.  
  319.   # Returns a string containing a human-readable representation of the
  320.   # ipaddr. ("#<IPAddr: family:address/mask>")
  321.   def inspect
  322.     case @family
  323.     when Socket::AF_INET
  324.       af = "IPv4"
  325.     when Socket::AF_INET6
  326.       af = "IPv6"
  327.     else
  328.       raise "unsupported address family"
  329.     end
  330.     return sprintf("#<%s: %s:%s/%s>", self.class.name,
  331.            af, _to_string(@addr), _to_string(@mask_addr))
  332.   end
  333.  
  334.   protected
  335.  
  336.   def set(addr, *family)
  337.     case family[0] ? family[0] : @family
  338.     when Socket::AF_INET
  339.       if addr < 0 || addr > IN4MASK
  340.     raise ArgumentError, "invalid address"
  341.       end
  342.     when Socket::AF_INET6
  343.       if addr < 0 || addr > IN6MASK
  344.     raise ArgumentError, "invalid address"
  345.       end
  346.     else
  347.       raise ArgumentError, "unsupported address family"
  348.     end
  349.     @addr = addr
  350.     if family[0]
  351.       @family = family[0]
  352.     end
  353.     return self
  354.   end
  355.  
  356.   def mask!(mask)
  357.     if mask.kind_of?(String)
  358.       if mask =~ /^\d+$/
  359.     prefixlen = mask.to_i
  360.       else
  361.     m = IPAddr.new(mask)
  362.     if m.family != @family
  363.       raise ArgumentError, "address family is not same"
  364.     end
  365.     @mask_addr = m.to_i
  366.     @addr &= @mask_addr
  367.     return self
  368.       end
  369.     else
  370.       prefixlen = mask
  371.     end
  372.     case @family
  373.     when Socket::AF_INET
  374.       if prefixlen < 0 || prefixlen > 32
  375.     raise ArgumentError, "invalid length"
  376.       end
  377.       masklen = 32 - prefixlen
  378.       @mask_addr = ((IN4MASK >> masklen) << masklen)
  379.     when Socket::AF_INET6
  380.       if prefixlen < 0 || prefixlen > 128
  381.     raise ArgumentError, "invalid length"
  382.       end
  383.       masklen = 128 - prefixlen
  384.       @mask_addr = ((IN6MASK >> masklen) << masklen)
  385.     else
  386.       raise "unsupported address family"
  387.     end
  388.     @addr = ((@addr >> masklen) << masklen)
  389.     return self
  390.   end
  391.  
  392.   private
  393.  
  394.   # Creates a new ipaddr containing the given human readable form of
  395.   # an IP address.  It also accepts `address/prefixlen' and
  396.   # `address/mask'.  When prefixlen or mask is specified, it returns a
  397.   # masked ipaddr.  IPv6 address may beenclosed with `[' and `]'.
  398.   #
  399.   # Although an address family is determined automatically from a
  400.   # specified address, you can specify an address family explicitly by
  401.   # the optional second argument.
  402.   def initialize(addr = '::', family = Socket::AF_UNSPEC)
  403.     if !addr.kind_of?(String)
  404.       if family != Socket::AF_INET6 && family != Socket::AF_INET
  405.     raise ArgumentError, "unsupported address family"
  406.       end
  407.       set(addr, family)
  408.       @mask_addr = (family == Socket::AF_INET) ? IN4MASK : IN6MASK
  409.       return
  410.     end
  411.     prefix, prefixlen = addr.split('/')
  412.     if prefix =~ /^\[(.*)\]$/i
  413.       prefix = $1
  414.       family = Socket::AF_INET6
  415.     end
  416.     # It seems AI_NUMERICHOST doesn't do the job.
  417.     #Socket.getaddrinfo(left, nil, Socket::AF_INET6, Socket::SOCK_STREAM, nil,
  418.     #               Socket::AI_NUMERICHOST)
  419.     begin
  420.       IPSocket.getaddress(prefix)        # test if address is vaild
  421.     rescue
  422.       raise ArgumentError, "invalid address"
  423.     end
  424.     @addr = @family = nil
  425.     if family == Socket::AF_UNSPEC || family == Socket::AF_INET
  426.       @addr = in_addr(prefix)
  427.       if @addr
  428.     @family = Socket::AF_INET
  429.       end
  430.     end
  431.     if !@addr && (family == Socket::AF_UNSPEC || family == Socket::AF_INET6)
  432.       @addr = in6_addr(prefix)
  433.       @family = Socket::AF_INET6
  434.     end
  435.     if family != Socket::AF_UNSPEC && @family != family
  436.       raise ArgumentError, "address family unmatch"
  437.     end
  438.     if prefixlen
  439.       mask!(prefixlen)
  440.     else
  441.       @mask_addr = (family == Socket::AF_INET) ? IN4MASK : IN6MASK
  442.     end
  443.   end
  444.  
  445.   def in_addr(addr)
  446.     if addr =~ /^\d+\.\d+\.\d+\.\d+$/
  447.       n = 0
  448.       addr.split('.').each { |i|
  449.     n <<= 8
  450.     n += i.to_i
  451.       }
  452.       return n
  453.     end
  454.     return nil
  455.   end
  456.  
  457.   def in6_addr(left)
  458.     case left
  459.     when /^::ffff:(\d+\.\d+\.\d+\.\d+)$/i
  460.       return in_addr($1) + 0xffff00000000
  461.     when /^::(\d+\.\d+\.\d+\.\d+)$/i
  462.       return in_addr($1)
  463.     when /[^0-9a-f:]/i
  464.       raise ArgumentError, "invalid address"
  465.     when /^(.*)::(.*)$/
  466.       left, right = $1, $2
  467.     else
  468.       right = ''
  469.     end
  470.     l = left.split(':')
  471.     r = right.split(':')
  472.     rest = 8 - l.size - r.size
  473.     if rest < 0
  474.       return nil
  475.     end
  476.     a = [l, Array.new(rest, '0'), r].flatten!
  477.     n = 0
  478.     a.each { |i|
  479.       n <<= 16
  480.       n += i.hex
  481.     }
  482.     return n
  483.   end
  484.  
  485.   def addr_mask(addr)
  486.     case @family
  487.     when Socket::AF_INET
  488.       addr &= IN4MASK
  489.     when Socket::AF_INET6
  490.       addr &= IN6MASK
  491.     else
  492.       raise "unsupported address family"
  493.     end
  494.     return addr
  495.   end
  496.  
  497.   def _reverse
  498.     case @family
  499.     when Socket::AF_INET
  500.       return (0..3).map { |i|
  501.     (@addr >> (8 * i)) & 0xff
  502.       }.join('.')
  503.     when Socket::AF_INET6
  504.       return ("%.32x" % @addr).reverse!.gsub!(/.(?!$)/, '\&.')
  505.     else
  506.       raise "unsupported address family"
  507.     end
  508.   end
  509.  
  510.   def _to_string(addr)
  511.     case @family
  512.     when Socket::AF_INET
  513.       return (0..3).map { |i|
  514.     (addr >> (24 - 8 * i)) & 0xff
  515.       }.join('.')
  516.     when Socket::AF_INET6
  517.       return (("%.32x" % addr).gsub!(/.{4}(?!$)/, '\&:'))
  518.     else
  519.       raise "unsupported address family"
  520.     end
  521.   end
  522.  
  523. end
  524.  
  525. if $0 == __FILE__
  526.   eval DATA.read, nil, $0, __LINE__+4
  527. end
  528.  
  529. __END__
  530.  
  531. require 'test/unit'
  532. require 'test/unit/ui/console/testrunner'
  533.  
  534. class TC_IPAddr < Test::Unit::TestCase
  535.   def test_s_new
  536.     assert_nothing_raised {
  537.       IPAddr.new("3FFE:505:ffff::/48")
  538.       IPAddr.new("0:0:0:1::")
  539.       IPAddr.new("2001:200:300::/48")
  540.     }
  541.  
  542.     a = IPAddr.new
  543.     assert_equal("::", a.to_s)
  544.     assert_equal("0000:0000:0000:0000:0000:0000:0000:0000", a.to_string)
  545.     assert_equal(Socket::AF_INET6, a.family)
  546.  
  547.     a = IPAddr.new("0123:4567:89ab:cdef:0ABC:DEF0:1234:5678")
  548.     assert_equal("123:4567:89ab:cdef:abc:def0:1234:5678", a.to_s)
  549.     assert_equal("0123:4567:89ab:cdef:0abc:def0:1234:5678", a.to_string)
  550.     assert_equal(Socket::AF_INET6, a.family)
  551.  
  552.     a = IPAddr.new("3ffe:505:2::/48")
  553.     assert_equal("3ffe:505:2::", a.to_s)
  554.     assert_equal("3ffe:0505:0002:0000:0000:0000:0000:0000", a.to_string)
  555.     assert_equal(Socket::AF_INET6, a.family)
  556.     assert_equal(false, a.ipv4?)
  557.     assert_equal(true, a.ipv6?)
  558.     assert_equal("#<IPAddr: IPv6:3ffe:0505:0002:0000:0000:0000:0000:0000/ffff:ffff:ffff:0000:0000:0000:0000:0000>", a.inspect)
  559.  
  560.     a = IPAddr.new("3ffe:505:2::/ffff:ffff:ffff::")
  561.     assert_equal("3ffe:505:2::", a.to_s)
  562.     assert_equal("3ffe:0505:0002:0000:0000:0000:0000:0000", a.to_string)
  563.     assert_equal(Socket::AF_INET6, a.family)
  564.  
  565.     a = IPAddr.new("0.0.0.0")
  566.     assert_equal("0.0.0.0", a.to_s)
  567.     assert_equal("0.0.0.0", a.to_string)
  568.     assert_equal(Socket::AF_INET, a.family)
  569.  
  570.     a = IPAddr.new("192.168.1.2")
  571.     assert_equal("192.168.1.2", a.to_s)
  572.     assert_equal("192.168.1.2", a.to_string)
  573.     assert_equal(Socket::AF_INET, a.family)
  574.     assert_equal(true, a.ipv4?)
  575.     assert_equal(false, a.ipv6?)
  576.  
  577.     a = IPAddr.new("192.168.1.2/24")
  578.     assert_equal("192.168.1.0", a.to_s)
  579.     assert_equal("192.168.1.0", a.to_string)
  580.     assert_equal(Socket::AF_INET, a.family)
  581.     assert_equal("#<IPAddr: IPv4:192.168.1.0/255.255.255.0>", a.inspect)
  582.  
  583.     a = IPAddr.new("192.168.1.2/255.255.255.0")
  584.     assert_equal("192.168.1.0", a.to_s)
  585.     assert_equal("192.168.1.0", a.to_string)
  586.     assert_equal(Socket::AF_INET, a.family)
  587.  
  588.     assert_equal("0:0:0:1::", IPAddr.new("0:0:0:1::").to_s)
  589.     assert_equal("2001:200:300::", IPAddr.new("2001:200:300::/48").to_s)
  590.  
  591.     assert_equal("2001:200:300::", IPAddr.new("[2001:200:300::]/48").to_s)
  592.  
  593.     [
  594.       ["fe80::1%fxp0"],
  595.       ["::1/255.255.255.0"],
  596.       ["::1:192.168.1.2/120"],
  597.       [IPAddr.new("::1").to_i],
  598.       ["::ffff:192.168.1.2/120", Socket::AF_INET],
  599.       ["[192.168.1.2]/120"],
  600.     ].each { |args|
  601.       assert_raises(ArgumentError) {
  602.     IPAddr.new(*args)
  603.       }
  604.     }
  605.   end
  606.  
  607.   def test_s_new_ntoh
  608.     addr = ''
  609.     IPAddr.new("1234:5678:9abc:def0:1234:5678:9abc:def0").hton.each_byte { |c|
  610.       addr += sprintf("%02x", c)
  611.     }
  612.     assert_equal("123456789abcdef0123456789abcdef0", addr)
  613.     addr = ''
  614.     IPAddr.new("123.45.67.89").hton.each_byte { |c|
  615.       addr += sprintf("%02x", c)
  616.     }
  617.     assert_equal(sprintf("%02x%02x%02x%02x", 123, 45, 67, 89), addr)
  618.     a = IPAddr.new("3ffe:505:2::")
  619.     assert_equal("3ffe:505:2::", IPAddr.new_ntoh(a.hton).to_s)
  620.     a = IPAddr.new("192.168.2.1")
  621.     assert_equal("192.168.2.1", IPAddr.new_ntoh(a.hton).to_s)
  622.   end
  623.  
  624.   def test_ipv4_compat
  625.     a = IPAddr.new("::192.168.1.2")
  626.     assert_equal("::192.168.1.2", a.to_s)
  627.     assert_equal("0000:0000:0000:0000:0000:0000:c0a8:0102", a.to_string)
  628.     assert_equal(Socket::AF_INET6, a.family)
  629.     assert_equal(true, a.ipv4_compat?)
  630.     b = a.native
  631.     assert_equal("192.168.1.2", b.to_s)
  632.     assert_equal(Socket::AF_INET, b.family)
  633.     assert_equal(false, b.ipv4_compat?)
  634.  
  635.     a = IPAddr.new("192.168.1.2")
  636.     b = a.ipv4_compat
  637.     assert_equal("::192.168.1.2", b.to_s)
  638.     assert_equal(Socket::AF_INET6, b.family)
  639.   end
  640.  
  641.   def test_ipv4_mapped
  642.     a = IPAddr.new("::ffff:192.168.1.2")
  643.     assert_equal("::ffff:192.168.1.2", a.to_s)
  644.     assert_equal("0000:0000:0000:0000:0000:ffff:c0a8:0102", a.to_string)
  645.     assert_equal(Socket::AF_INET6, a.family)
  646.     assert_equal(true, a.ipv4_mapped?)
  647.     b = a.native
  648.     assert_equal("192.168.1.2", b.to_s)
  649.     assert_equal(Socket::AF_INET, b.family)
  650.     assert_equal(false, b.ipv4_mapped?)
  651.  
  652.     a = IPAddr.new("192.168.1.2")
  653.     b = a.ipv4_mapped
  654.     assert_equal("::ffff:192.168.1.2", b.to_s)
  655.     assert_equal(Socket::AF_INET6, b.family)
  656.   end
  657.  
  658.   def test_reverse
  659.     assert_equal("f.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.0.0.5.0.5.0.e.f.f.3.ip6.arpa", IPAddr.new("3ffe:505:2::f").reverse)
  660.     assert_equal("1.2.168.192.in-addr.arpa", IPAddr.new("192.168.2.1").reverse)
  661.   end
  662.  
  663.   def test_ip6_arpa
  664.     assert_equal("f.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.0.0.5.0.5.0.e.f.f.3.ip6.arpa", IPAddr.new("3ffe:505:2::f").ip6_arpa)
  665.     assert_raises(ArgumentError) {
  666.       IPAddr.new("192.168.2.1").ip6_arpa
  667.     }
  668.   end
  669.  
  670.   def test_ip6_int
  671.     assert_equal("f.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.0.0.5.0.5.0.e.f.f.3.ip6.int", IPAddr.new("3ffe:505:2::f").ip6_int)
  672.     assert_raises(ArgumentError) {
  673.       IPAddr.new("192.168.2.1").ip6_int
  674.     }
  675.   end
  676.  
  677.   def test_to_s
  678.     assert_equal("3ffe:0505:0002:0000:0000:0000:0000:0001", IPAddr.new("3ffe:505:2::1").to_string)
  679.     assert_equal("3ffe:505:2::1", IPAddr.new("3ffe:505:2::1").to_s)
  680.   end
  681. end
  682.  
  683. class TC_Operator < Test::Unit::TestCase
  684.  
  685.   IN6MASK32  = "ffff:ffff::"
  686.   IN6MASK128 = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"
  687.  
  688.   def setup
  689.     @in6_addr_any = IPAddr.new()
  690.     @a = IPAddr.new("3ffe:505:2::/48")
  691.     @b = IPAddr.new("0:0:0:1::")
  692.     @c = IPAddr.new(IN6MASK32)
  693.   end
  694.   alias set_up setup
  695.  
  696.   def test_or
  697.     assert_equal("3ffe:505:2:1::", (@a | @b).to_s)
  698.     a = @a
  699.     a |= @b
  700.     assert_equal("3ffe:505:2:1::", a.to_s)
  701.     assert_equal("3ffe:505:2::", @a.to_s)
  702.     assert_equal("3ffe:505:2:1::",
  703.          (@a | 0x00000000000000010000000000000000).to_s)
  704.   end
  705.  
  706.   def test_and
  707.     assert_equal("3ffe:505::", (@a & @c).to_s)
  708.     a = @a
  709.     a &= @c
  710.     assert_equal("3ffe:505::", a.to_s)
  711.     assert_equal("3ffe:505:2::", @a.to_s)
  712.     assert_equal("3ffe:505::", (@a & 0xffffffff000000000000000000000000).to_s)
  713.   end
  714.  
  715.   def test_shift_right
  716.     assert_equal("0:3ffe:505:2::", (@a >> 16).to_s)
  717.     a = @a
  718.     a >>= 16
  719.     assert_equal("0:3ffe:505:2::", a.to_s)
  720.     assert_equal("3ffe:505:2::", @a.to_s)
  721.   end
  722.  
  723.   def test_shift_left
  724.     assert_equal("505:2::", (@a << 16).to_s)
  725.     a = @a
  726.     a <<= 16
  727.     assert_equal("505:2::", a.to_s)
  728.     assert_equal("3ffe:505:2::", @a.to_s)
  729.   end
  730.  
  731.   def test_carrot
  732.     a = ~@in6_addr_any
  733.     assert_equal(IN6MASK128, a.to_s)
  734.     assert_equal("::", @in6_addr_any.to_s)
  735.   end
  736.  
  737.   def test_equal
  738.     assert_equal(true, @a == IPAddr.new("3ffe:505:2::"))
  739.     assert_equal(false, @a == IPAddr.new("3ffe:505:3::"))
  740.     assert_equal(true, @a != IPAddr.new("3ffe:505:3::"))
  741.     assert_equal(false, @a != IPAddr.new("3ffe:505:2::"))
  742.   end
  743.  
  744.   def test_mask
  745.     a = @a.mask(32)
  746.     assert_equal("3ffe:505::", a.to_s)
  747.     assert_equal("3ffe:505:2::", @a.to_s)
  748.   end
  749.  
  750.   def test_include?
  751.     assert_equal(true, @a.include?(IPAddr.new("3ffe:505:2::")))
  752.     assert_equal(true, @a.include?(IPAddr.new("3ffe:505:2::1")))
  753.     assert_equal(false, @a.include?(IPAddr.new("3ffe:505:3::")))
  754.     net1 = IPAddr.new("192.168.2.0/24")
  755.     assert_equal(true, net1.include?(IPAddr.new("192.168.2.0")))
  756.     assert_equal(true, net1.include?(IPAddr.new("192.168.2.255")))
  757.     assert_equal(false, net1.include?(IPAddr.new("192.168.3.0")))
  758.     # test with integer parameter
  759.     int = (192 << 24) + (168 << 16) + (2 << 8) + 13
  760.  
  761.     assert_equal(true, net1.include?(int))
  762.     assert_equal(false, net1.include?(int+255))
  763.  
  764.   end
  765.  
  766. end
  767.